package com.helloworld.upload.domain;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.helloworld.common.dao.SimpleBizDao;

/**
 * 엑셀데이터 검증에 필요한 정보를 보관
 * @author 박형일
 */
public class ValidateRule {
	private static final Logger logger = LoggerFactory.getLogger(ValidateRule.class);
	
	// validateRule, 
	//		type: TYPE_SIZE,
	//			fieldType: string, number, date, datetime
	//			size: 
	//		type: RI,
	//			table:
	//			column:
	//		type: RI_REPLACE
	//			table:
	//			column:
	//			return:		
	
	/**
	 * 검증룰 구분 - TypeSize:데이터 타입 및 길이 확인, RI:참조테이블에 존재여부 확인, RiReplace:참조테이블의 다른 필드로 대치
	 * @author 박형일
	 */
	public enum EnumRule {TypeSize, RI, RiReplace, Null, Const};
	
	public static class TypeSize {
		public static final String FieldType = "field.type";
		public enum EnumFieldType {VARCHAR2, NUMBER, DATE, TIMESTAMP};
	}
	
	public static class RI {
		public static final String Table = "table";
		public static final String Column = "column";
		public static final String ReturnColumn = "return.column";
		public static final String SQL = "sql";
		public static final String lookup = "lookup";
	}
	
	public static class Const {
		public static final String value = "value";
	}

	public static final int ERR_KEY_INDEX = 0;
	public static final int ERR_MSG_INDEX = 1;
	
	public static class Err {
		public static final String[] TypeNotMatch = {"type.not.match", "형식이 같지 않습니다. 기대값:[%s], 데이터값[%s]"};
		public static final String[] OverSize = {"over.size", "길이가 초과 했습니다. 기대값:[%d.%d], 데이터값:[%d.%d]"};
		public static final String[] BooleanNotAllowed = {"boolean.not.allowed", "Boolean 값은 허용되지 않습니다."};
		public static final String[] FormulaNotAllowed = {"formula.not.allowed", "수식은 허용되지 않습니다."};
		public static final String[] ReferenceNotFound = {"reference.not.found", "참조테이블에 값이 포함되어 있지 않습니다."};
		public static final String[] ReferenceIsNull = {"reference.is.null", "참조테이블의 조회값이 빈값입니다."};
		public static final String[] ValueIsNull = {"value.is.null", "빈값이 허용되지 않습니다."};
	}
	
	public static class Lookup {
		public static final String MAP_KEY_CODE = "CODE";
		public static final String MAP_KEY_VALUE = "VALUE";
	}
	
	private ColumnInfo holder;
	
	public void setColumnInfo(ColumnInfo holder) {
		this.holder = holder;
	}
	
	public ColumnInfo getColumnInfo() {
		return holder;
	}
	
		private SimpleBizDao getDao() {
			SimpleBizDao dao = null;
			logger.debug("*** holder:" + holder);
			logger.debug("*** holder.getUploadInfo():" + holder.getUploadInfo());
			if (holder != null && holder.getUploadInfo() != null) {
				dao = holder.getUploadInfo().getDao();
			}
			return dao;
		}
		
		private Map<String, Object> makeLookup(String sql) {
			SimpleBizDao dao = getDao();
			
			Map<String, Object> lookup = null;
			
			if (dao != null) {
				List<Map<String, Object>> list = dao.listSQL(sql);
				
				if (list != null) {
					lookup = new HashMap<String, Object>();
					for (Map<String, Object> map : list) {
						lookup.put((String)map.get(Lookup.MAP_KEY_CODE), map.get(Lookup.MAP_KEY_VALUE));
					}
				}
			}
			
			return lookup;
		}
	
	private EnumRule rule;

	public EnumRule getRule() {
		return rule;
	}

	public void setRule(EnumRule rule) {
		this.rule = rule;
	}
	
	private Map<String, Object> info;

	/**
	 * 
	 */
	public void setRuleTypeSize() {
		rule = EnumRule.TypeSize;
	}	
	
	public TypeSize.EnumFieldType getRuleFieldType() {
		if (rule != EnumRule.TypeSize) { throw new RuntimeException("rule is not 'TypeSize'"); }
		if (holder != null) { return holder.getFieldType(); }
		return null;
	}
	
	public int getRuleItemSize() {
		if (rule != EnumRule.TypeSize) { throw new RuntimeException("rule is not 'TypeSize'"); }
		if (holder != null) { return holder.getSize(); }
		return -1;
	}

	public int getRuleItemScale() {
		if (rule != EnumRule.TypeSize) { throw new RuntimeException("rule is not 'TypeSize'"); }
		if (holder != null) { return holder.getScale(); }
		return -1;
	}
	
	/**
	 * 
	 * @param table
	 * @param column
	 */
	public void setRuleRI(String table, String column) {
		rule = EnumRule.RI;
		
		info = new HashMap<String, Object>();
		info.put(RI.Table, table);
		info.put(RI.Column, column);
	}
	
	/**
	 * @param sql
	 */
	public void setRuleRI(String sql) {
		rule = EnumRule.RI;
		
		info = new HashMap<String, Object>();
		info.put(RI.SQL, sql);
		info.put(RI.lookup, makeLookup(sql));
	}	
	
	public String getRuleItemTable() {
		if (rule != EnumRule.RI && rule != EnumRule.RiReplace) { throw new RuntimeException("rule is not 'RI' or 'RiReplace'"); }
		
		if (info != null) { return (String)info.get(RI.Table); }
		return null;
	}
	
	public String getRuleItemColumn() {
		if (rule != EnumRule.RI && rule != EnumRule.RiReplace) { throw new RuntimeException("rule is not 'RI' or 'RiReplace'"); }
		
		if (info != null) { return (String)info.get(RI.Column); }
		return null;
	}	
	
	public String getRuleItemSQL() {
		if (rule != EnumRule.RI && rule != EnumRule.RiReplace) { throw new RuntimeException("rule is not 'RI' or 'RiReplace'"); }
		
		if (info != null) { return (String)info.get(RI.SQL); }
		return null;
	}	
	
	/**
	 * @param table
	 * @param column
	 * @param returnColumn
	 */
	public void setRuleRiReplace(String table, String column, String returnColumn) {
		rule = EnumRule.RiReplace;
		
		info = new HashMap<String, Object>();
		info.put(RI.Table, table);
		info.put(RI.Column, column);
		info.put(RI.ReturnColumn, returnColumn);
	}
	
	/**
	 * @param sql
	 */
	public void setRuleRiReplace(String sql) {
		rule = EnumRule.RiReplace;
		
		info = new HashMap<String, Object>();
		info.put(RI.SQL, sql);
		info.put(RI.lookup, makeLookup(sql));
	}	
	
	public String getRuleItemReturnColumn() {
		if (rule != EnumRule.RiReplace) { throw new RuntimeException("rule is not 'RiReplace'"); }
		
		if (info != null) { return (String)info.get(RI.ReturnColumn); }
		return null;
	}
	
	/**
	 * 
	 */
	public void setRuleNull() {
		rule = EnumRule.Null;
	}
	
	/**
	 * @param value
	 */
	public void setRuleConst(String value) {
		rule = EnumRule.Const;
		
		info = new HashMap<String, Object>();
		info.put(Const.value, value);
		
		// 엑셀의 컬럼을 지정할 수 없는 상태이므로 -1 지정
		if (holder != null) { holder.setSourceColumnIndex(-1); }
		
	}
	
	public String getRuleItemValue() {
		if (rule != EnumRule.Const) { throw new RuntimeException("rule is not 'Const'"); }
		
		if (info != null) { return (String)info.get(Const.value); }
		return null;	
	}
	
	public Map<String, Object> getLookup() {
		return (Map<String, Object>)info.get(RI.lookup);
	}
	
	@Override
	public String toString() {
		StringBuilder builder = new StringBuilder();
		builder
			.append("{")
			.append("rule:").append(rule.name())
			.append(",info:").append(info.toString());
		
		return builder.toString();
	}
}
